// src/utils/ffmpeg.ts

const path = window.electronAPI.path
const fs = window.electronAPI.fs

export interface VideoProcessOptions {
  // 基本参数
  startTime?: number;
  duration?: number;
  format?: string;

  // 视频参数
  videoCodec?: string;
  videoBitrate?: string;
  width?: number;
  height?: number;
  fps?: number;
  aspect?: string;

  // 音频参数
  audioCodec?: string;
  audioBitrate?: string;
  audioChannels?: number;
  audioFrequency?: number;

  // 高级参数
  speed?: number; // 视频加速倍数
  volume?: number; // 音量调节倍数
}

export interface VideoInfo {
  format: {
    duration: string;
    size: string;
    bit_rate: string;
  };
  streams: Array<{
    codec_type: string;
    codec_name: string;
    width?: number;
    height?: number;
    duration?: string;
    bit_rate?: string;
  }>;
}

export class VideoProcessor {
  private ffmpegPath: string;
  private ffprobePath: string;

  constructor(ffmpegPath?: string, ffprobePath?: string) {
    // 使用项目根目录下的 ffmpeg

    this.ffmpegPath = ffmpegPath || path.join(__dirname, '../resource', 'ffmpeg', 'bin', 'ffmpeg.exe');
    this.ffprobePath = ffprobePath || path.join(__dirname, '../resource', 'ffmpeg', 'bin', 'ffprobe.exe');

    // 检查 ffmpeg 和 ffprobe 是否存在
    if (!fs.existsSync(this.ffmpegPath)) {
      throw new Error(`FFmpeg executable not found at: ${this.ffmpegPath}`);
    }

    if (!fs.existsSync(this.ffprobePath)) {
      throw new Error(`FFprobe executable not found at: ${this.ffprobePath}`);
    }
  }

  /**
   * 随机选择视频并处理后合并
   * @param folderPath 视频文件夹路径
   * @param videoCount 需要选择的视频数量
   * @param outputPath 输出视频路径
   * @param options 处理选项
   * @returns Promise<void>
   */
  public async randomSelectAndMerge(
    folderPath: string,
    videoCount: number,
    outputPath: string,
    options: {
      // 时间截取参数 (百分比)
      startPercent?: number; // 开始时间百分比 (0-100)
      endPercent?: number;   // 结束时间百分比 (0-100)
      // 加速倍数
      speed?: number;
      // 输出格式
      format?: string;
    } = {}
  ): Promise<void> {
    // 检查文件夹是否存在
    if (!fs.existsSync(folderPath)) {
      throw new Error(`文件夹不存在: ${folderPath}`);
    }

    // 获取文件夹中的所有视频文件
    const files = fs.readdirSync(folderPath);
    const videoFiles = files.filter((file: string) => {
      const ext = path.extname(file).toLowerCase();
      return ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv', '.webm'].includes(ext);
    });

    if (videoFiles.length === 0) {
      throw new Error(`文件夹中没有找到视频文件: ${folderPath}`);
    }

    if (videoCount > videoFiles.length) {
      throw new Error(`文件夹中只有 ${videoFiles.length} 个视频文件，无法选择 ${videoCount} 个`);
    }

    // 随机选择指定数量的视频
    const selectedVideos = this.getRandomElements(videoFiles, videoCount)
      .map(file => path.join(folderPath, file));

    // 创建临时目录用于存储处理后的视频
    const tempDir = path.join(path.dirname(outputPath), 'temp_processing');
    if (!fs.existsSync(tempDir)) {
      fs.mkdirSync(tempDir, { recursive: true });
    }

    try {
      // 处理每个选中的视频
      const processedVideos: string[] = [];

      for (let i = 0; i < selectedVideos.length; i++) {
        const inputPath = selectedVideos[i];
        const processedPath = path.join(tempDir, `processed_${i}_${path.basename(inputPath)}`);

        // 获取视频信息以确定时长
        const videoInfo = await this.getVideoInfo(inputPath);
        const duration = parseFloat(videoInfo.format.duration);

        // 计算截取时间段
        let startTime = 0;
        let processDuration = duration;

        if (options.startPercent !== undefined && options.endPercent !== undefined) {
          // 确保开始百分比小于结束百分比
          const startPercent = Math.max(0, Math.min(100, options.startPercent));
          const endPercent = Math.max(0, Math.min(100, options.endPercent));

          if (startPercent >= endPercent) {
            throw new Error('开始百分比必须小于结束百分比');
          }

          startTime = (duration * startPercent) / 100;
          processDuration = (duration * (endPercent - startPercent)) / 100;
        }

        // 构建处理选项
        const processOptions: VideoProcessOptions = {
          startTime: startTime,
          duration: processDuration
        };

        // 设置加速
        if (options.speed && options.speed !== 1) {
          processOptions.speed = options.speed;
        }

        // 设置输出格式
        if (options.format) {
          processOptions.format = options.format;
        }

        // 处理视频
        await this.transcode(inputPath, processedPath, processOptions);
        processedVideos.push(processedPath);
      }

      // 合并处理后的视频
      await this.merge(processedVideos, outputPath);

      // 清理临时文件
      this.cleanupTempFiles(tempDir);

      console.log(`成功处理并合并 ${videoCount} 个视频到: ${outputPath}`);
    } catch (error) {
      // 清理临时文件
      this.cleanupTempFiles(tempDir);
      throw error;
    }
  }

  // 辅助方法：从数组中随机选择指定数量的元素
  private getRandomElements<T>(array: T[], count: number): T[] {
    const shuffled = [...array].sort(() => 0.5 - Math.random());
    return shuffled.slice(0, count);
  }

  // 辅助方法：清理临时文件
  private cleanupTempFiles(tempDir: string): void {
    try {
      if (fs.existsSync(tempDir)) {
        const files = fs.readdirSync(tempDir);
        for (const file of files) {
          const filePath = path.join(tempDir, file);
          if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
          }
        }
        fs.rmdirSync(tempDir);
      }
    } catch (error) {
      console.warn('清理临时文件失败:', error);
    }
  }

  /**
   * 获取视频信息
   * @param inputPath 输入视频路径
   * @returns Promise<VideoInfo>
   */
  public async getVideoInfo(inputPath: string): Promise<VideoInfo> {
    const command = `"${this.ffprobePath}" -v quiet -print_format json -show_format -show_streams "${inputPath}"`;

    try {
      const { stdout } = await window.electronAPI.ffmpegExecPromise(command);
      return JSON.parse(stdout) as VideoInfo;
    } catch (error) {
      throw new Error(`获取视频信息失败: ${error}`);
    }
  }

  /**
 * 视频转码
 * @param inputPath 输入视频路径
 * @param outputPath 输出视频路径
 * @param options 转码选项
 * @returns Promise<void>
 */
public transcode(inputPath: string, outputPath: string, options: VideoProcessOptions = {}): Promise<void> {
  return new Promise((resolve, reject) => {
    // 初始化命令参数数组，-y 参数用于覆盖已存在的输出文件
    const cmdArgs: string[] = ['-y'];

    // 设置输入文件路径
    cmdArgs.push('-i', `"${inputPath}"`);

    // 设置时间参数
    // -ss 参数设置开始时间点
    if (options.startTime !== undefined) {
      cmdArgs.push('-ss', options.startTime.toString());
    }

    // -t 参数设置处理时长
    if (options.duration !== undefined) {
      cmdArgs.push('-t', options.duration.toString());
    }

    // 设置视频编码参数
    if (options.videoCodec) {
      // 使用指定的视频编码器
      cmdArgs.push('-vcodec', options.videoCodec);
    } else {
      // 默认使用 libx264 编码器
      cmdArgs.push('-vcodec', 'libx264');
    }

    // 设置视频比特率，控制视频质量与文件大小
    if (options.videoBitrate) {
      cmdArgs.push('-b:v', options.videoBitrate);
    }

    // 设置视频分辨率尺寸
    if (options.width && options.height) {
      cmdArgs.push('-s', `${options.width}x${options.height}`);
    }

    // 设置视频帧率
    if (options.fps) {
      cmdArgs.push('-r', options.fps.toString());
    }

    // 设置视频宽高比
    if (options.aspect) {
      cmdArgs.push('-aspect', options.aspect);
    }

    // 设置音频编码参数
    if (options.audioCodec) {
      // 使用指定的音频编码器
      cmdArgs.push('-acodec', options.audioCodec);
    } else {
      // 默认使用 aac 音频编码器
      cmdArgs.push('-acodec', 'aac');
    }

    // 设置音频比特率
    if (options.audioBitrate) {
      cmdArgs.push('-b:a', options.audioBitrate);
    }

    // 设置音频声道数
    if (options.audioChannels) {
      cmdArgs.push('-ac', options.audioChannels.toString());
    }

    // 设置音频采样率
    if (options.audioFrequency) {
      cmdArgs.push('-ar', options.audioFrequency.toString());
    }

    // 设置输出格式
    if (options.format) {
      cmdArgs.push('-f', options.format);
    }

    // 设置视频过滤器（包括裁剪和加速）
    const filters: string[] = [];

    // 设置视频加速效果
    // 通过调整时间戳来实现视频加速或减速
    if (options.speed && options.speed !== 1) {
      filters.push(`setpts=${1/options.speed}*PTS`);
    }

    // 设置音频过滤器（音量和加速）
    const audioFilters: string[] = [];

    // 设置音量调节
    if (options.volume && options.volume !== 1) {
      audioFilters.push(`volume=${options.volume}`);
    }

    // 设置音频加速效果
    if (options.speed && options.speed !== 1) {
      if (options.speed <= 2) {
        // 速度在2倍以内可以直接使用 atempo 过滤器
        audioFilters.push(`atempo=${options.speed}`);
      } else {
        // 对于大于2倍的速度，需要链式使用 atempo
        const atempoChain = this.generateAtempoChain(options.speed);
        audioFilters.push(atempoChain);
      }
    }

    // 如果有视频过滤器则添加到命令中
    if (filters.length > 0) {
      cmdArgs.push('-vf', `"${filters.join(',')}"`);
    }

    // 如果有音频过滤器则添加到命令中
    if (audioFilters.length > 0) {
      cmdArgs.push('-af', `"${audioFilters.join(',')}"`);
    }

    // 设置输出文件路径
    cmdArgs.push(`"${outputPath}"`);

    // 构建完整的 ffmpeg 命令
    const command = `"${this.ffmpegPath}" ${cmdArgs.join(' ')}`;
    console.log('FFmpeg启动命令:', command);

    // 执行 ffmpeg 命令
    window.electronAPI.ffmpegExec(command, (error: Error | null) => {
      if (error) {
        console.error('转码失败:', error.message);
        reject(new Error(`转码失败: ${error.message}`));
        return;
      }
      console.log('转码完成');
      resolve();
    });
  });
}


  /**
   * 视频剪辑
   * @param inputPath 输入视频路径
   * @param outputPath 输出视频路径
   * @param startTime 开始时间(秒)
   * @param duration 持续时间(秒)
   * @returns Promise<void>
   */
  public clip(inputPath: string, outputPath: string, startTime: number, duration: number): Promise<void> {
    return this.transcode(inputPath, outputPath, { startTime, duration });
  }

  /**
   * 视频合并
   * @param inputPaths 输入视频路径数组
   * @param outputPath 输出视频路径
   * @returns Promise<void>
   */
  public merge(inputPaths: string[], outputPath: string): Promise<void> {
    return new Promise(async (resolve, reject) => {
      // 创建临时文件列表
      const tempDir = path.dirname(outputPath);
      const fileListPath = path.join(tempDir, 'file_list.txt');

      const fileContent = inputPaths
        .filter(filePath => fs.existsSync(filePath))
        .map(filePath => `file '${filePath.replace(/'/g, "\\'")}'`)
        .join('\n');

      if (!fileContent) {
        reject(new Error('没有有效的输入文件'));
        return;
      }

      fs.writeFileSync(fileListPath, fileContent);

      const command = `"${this.ffmpegPath}" -y -f concat -safe 0 -i "${fileListPath}" -c copy "${outputPath}"`;
      console.log('合并命令:', command);

      try {
        await window.electronAPI.ffmpegExecPromise(command);
        // 清理临时文件
        try {
          fs.unlinkSync(fileListPath);
        } catch (err) {
          console.warn('清理临时文件失败:', err);
        }
        console.log('合并完成');
        resolve();
      } catch (error) {
        // 清理临时文件
        try {
          fs.unlinkSync(fileListPath);
        } catch (err) {
          console.warn('清理临时文件失败:', err);
        }
        console.error('合并失败:', error);
        reject(new Error(`合并失败: ${error}`));
      }
    });
  }

  /**
   * 视频截图
   * @param inputPath 输入视频路径
   * @param outputPath 输出图片路径
   * @param timestamp 截图时间点(秒)
   * @param size 图片尺寸 (例如: '640x480')
   * @returns Promise<void>
   */
  public screenshot(inputPath: string, outputPath: string, timestamp: number, size?: string): Promise<void> {
    return new Promise((resolve, reject) => {
      const cmdArgs: string[] = [
        '-y',
        '-i', `"${inputPath}"`,
        '-ss', timestamp.toString(),
        '-vframes', '1'
      ];

      if (size) {
        cmdArgs.push('-s', size);
      }

      cmdArgs.push(`"${outputPath}"`);

      const command = `"${this.ffmpegPath}" ${cmdArgs.join(' ')}`;
      console.log('截图命令:', command);

      window.electronAPI.ffmpegExec(command, (error: Error | null) => {
        if (error) {
          console.error('截图失败:', error.message);
          reject(new Error(`截图失败: ${error.message}`));
          return;
        }
        console.log('截图完成');
      }).then(r => {
        console.log(r)
        resolve();
      });
    });
  }

  /**
   * 视频压缩
   * @param inputPath 输入视频路径
   * @param outputPath 输出视频路径
   * @param quality 压缩质量 (0-100, 数值越小质量越低)
   * @returns Promise<void>
   */
  public compress(inputPath: string, outputPath: string, quality: number = 50): Promise<void> {
    // 根据质量参数计算比特率
    const videoBitrate = Math.max(100, Math.min(5000, 5000 * (quality / 100)));
    const audioBitrate = Math.max(32, Math.min(256, 256 * (quality / 100)));

    return this.transcode(inputPath, outputPath, {
      videoCodec: 'libx264',
      videoBitrate: `${videoBitrate}k`,
      audioCodec: 'aac',
      audioBitrate: `${audioBitrate}k`,
      format: 'mp4'
    });
  }

  /**
   * 视频加速/减速
   * @param inputPath 输入视频路径
   * @param outputPath 输出视频路径
   * @param speed 速度倍数 (0.5 = 减速一半, 2 = 加速一倍)
   * @returns Promise<void>
   */
  public changeSpeed(inputPath: string, outputPath: string, speed: number): Promise<void> {
    return this.transcode(inputPath, outputPath, { speed });
  }

  /**
   * 调节音量
   * @param inputPath 输入视频路径
   * @param outputPath 输出视频路径
   * @param volume 音量倍数 (0.5 = 降低一半, 2 = 提高一倍)
   * @returns Promise<void>
   */
  public adjustVolume(inputPath: string, outputPath: string, volume: number): Promise<void> {
    return this.transcode(inputPath, outputPath, { volume });
  }

  /**
   * 转换格式
   * @param inputPath 输入视频路径
   * @param outputPath 输出视频路径
   * @param format 目标格式
   * @returns Promise<void>
   */
  public convertFormat(inputPath: string, outputPath: string, format: string): Promise<void> {
    return this.transcode(inputPath, outputPath, { format });
  }

  /**
   * 获取支持的格式列表
   * @returns string[]
   */
  public getSupportedFormats(): string[] {
    return ['mp4', 'avi', 'mov', 'mkv', 'flv', 'wmv', 'webm'];
  }

  /**
   * 获取支持的视频编码器列表
   * @returns string[]
   */
  public getSupportedVideoCodecs(): string[] {
    return ['libx264', 'libx265', 'mpeg4', 'vp8', 'vp9'];
  }

  /**
   * 获取支持的音频编码器列表
   * @returns string[]
   */
  public getSupportedAudioCodecs(): string[] {
    return ['aac', 'mp3', 'vorbis', 'opus'];
  }

  // 私有辅助方法
  private generateAtempoChain(speed: number): string {
    if (speed <= 2) {
      return `atempo=${speed}`;
    }

    // 对于大于2倍的速度，需要链式使用atempo (每个atempo最大支持2倍)
    const chain = [];
    let remainingSpeed = speed;

    while (remainingSpeed > 2) {
      chain.push('atempo=2.0');
      remainingSpeed /= 2;
    }

    if (remainingSpeed > 1) {
      chain.push(`atempo=${remainingSpeed}`);
    }

    return chain.join(',');
  }
}

// 导出默认实例
export default new VideoProcessor();
